package com.hx.service.Impl;

import com.hx.dto.MoodDTO;
import com.hx.dto.UserDTO;
import com.hx.mapper.MoodMapper;
import com.hx.mapper.UserMapper;
import com.hx.mq.MoodProducer;
import com.hx.pojo.Mood;
import com.hx.pojo.User;
import com.hx.pojo.UserMoodPraiseRel;
import com.hx.service.MoodService;
import com.hx.service.UserMoodPraiseRelService;
import com.hx.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.jms.Destination;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;


@Service
@Slf4j
public class MoodServiceImpl implements MoodService {

    @Autowired
    private MoodMapper moodMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserService userService;

    @Autowired
    private UserMoodPraiseRelService userMoodPraiseRelService;

    @Resource
    private RedisTemplate redisTemplate;

    //用于存放不同说说id的redis(HashSet)的主键key,value对应不同的说说id
    private static final String PRAISE_HASH_KEY = "praise.mood.id.list.key";

    @Resource
    private MoodProducer moodProducer;

    //queue队列名称 与xml配置文件里的destination保持一致
    private static Destination destination = new ActiveMQQueue("praise_num_queue");

    /**
     * 查找所有说说列表  (mysql)
     * 展示DTO对象给前端
     * @return
     */
    @Override
    public List<MoodDTO> findAllMoods() {
        List<Mood> moodList = moodMapper.findAllMoods();
        return convertPojoToDTO(moodList);
    }

    /**
     * 查找所有说说列表  (redis + mysql)
     * 展示DTO对象给前端
     * @return
     */
    @Override
    public List<MoodDTO> findAllMoodsByRedis() {

        //mysql中已存的数据
        List<Mood> moodList = moodMapper.findAllMoods();
        if (CollectionUtils.isEmpty(moodList)){
            log.info("mysql中未查询到说说记录");
            return Collections.EMPTY_LIST;
        }

        //展成前端DTO对象
        List<MoodDTO> moodDTOArrayList = new ArrayList<>();
        for (Mood mood : moodList) {

            MoodDTO moodDTO = new MoodDTO();
            moodDTO.setId(mood.getId());
            moodDTO.setUserId(mood.getUserId());
            moodDTO.setContent(mood.getContent());
            moodDTO.setPublishTime(mood.getPublishTime());

            UserDTO userDTO = userService.findUserById(mood.getUserId());
            moodDTO.setUserName(userDTO.getName());
            moodDTO.setUserAccount(userDTO.getAccount());

            //点赞记录:mysql+redis
            moodDTO.setPraiseNum(mood.getPraiseNum() +
                    redisTemplate.opsForSet().size(mood.getId()).intValue());

            moodDTOArrayList.add(moodDTO);
        }
        return moodDTOArrayList;
    }

    /**
     * 根据id查询说说记录
     * @param id
     * @return
     */
    @Override
    public Mood findMoodById(String id) {
        return moodMapper.findMoodById(id);
    }

    /**
     * 更新说说的信息，例如：内容、点赞数
     * @param mood
     * @return
     */
    @Override
    public boolean updateMood(Mood mood) {
        return moodMapper.updateMood(mood);
    }

    /**
     * 将pojo对象转化成DTO对象
     * @param moodList
     * @return
     */
    private List<MoodDTO> convertPojoToDTO(List<Mood> moodList) {

        if (CollectionUtils.isEmpty(moodList)){
            log.error("mood 列表查询为空！");
            return Collections.EMPTY_LIST;
        }

        List<MoodDTO> moodDTOArrayList = new ArrayList<>();
        for (Mood mood : moodList) {

            MoodDTO moodDTO = new MoodDTO();
            moodDTO.setId(mood.getId());
            moodDTO.setUserId(mood.getUserId());
            moodDTO.setContent(mood.getContent());
            moodDTO.setPublishTime(mood.getPublishTime());
            moodDTO.setPraiseNum(mood.getPraiseNum());

            User user = userMapper.findUserById(mood.getUserId());
            moodDTO.setUserName(user.getName());
            moodDTO.setUserAccount(user.getAccount());

            moodDTOArrayList.add(moodDTO);
        }

        return moodDTOArrayList;
    }

    /**
     * 指定用户id 点赞 指定说说id
     * @param userId
     * @param moodId
     * @return
     */
    public boolean praiseMood(String userId,String moodId){

        //保存点赞记录
        UserMoodPraiseRel userMoodPraiseRel = new UserMoodPraiseRel();
        userMoodPraiseRel.setUserId(userId);
        userMoodPraiseRel.setMoodId(moodId);
        userMoodPraiseRelService.save(userMoodPraiseRel);
        log.info("用户{}成功点赞说说{}",userId,moodId);

        //更新点赞数目
        Mood mood = this.findMoodById(moodId);
        if (Objects.isNull(mood)){
            log.error("并未查找到moodId为{}的说说记录",moodId);
        }
        mood.setPraiseNum(mood.getPraiseNum() + 1);

        //更新说说信息
        this.updateMood(mood);
        log.info("成功点赞，点赞数变更为:{}",mood.getPraiseNum());

        return Boolean.TRUE;

    }

    /**
     * 点赞说说 缓存在redis中
     * 使用Set集合来存放有一个好处: 去重，实现一个用户只点赞一次，接口幂等性。
     * @param userId
     * @param moodId
     * @return
     */
    @Override
    public boolean praiseMoodByRedis(String userId, String moodId) {

        //redis中存放不同的说说id  set(key,List<moodId>)
        redisTemplate.opsForSet().add(PRAISE_HASH_KEY,moodId);

        //set(moodId,List<userId>)   size()可统计redis点赞数
        redisTemplate.opsForSet().add(moodId,userId);

        log.info("点赞记录缓存在redis中...");
        return true;
    }

    /**
     * 点赞说说 使用mq进行异步解耦
     * @param userId
     * @param moodId
     * @return
     */
    @Override
    public boolean praiseMoodByMQ(String userId, String moodId) {

        //创建消息
        MoodDTO moodDTO = new MoodDTO();
        moodDTO.setUserId(userId);
        moodDTO.setId(moodId);

        //生产者生产消息
        moodProducer.sendMessage(destination,moodDTO);
        log.info("生产者成功生产消息...");
        return true;
    }
}
